package com.github.cosycode.imgtool.rule;

import com.github.cosycode.imgtool.tool.BaseTool;
import com.github.cosycode.imgtool.util.HttpUtils;
import com.github.cosycode.imgtool.util.PathUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import java.io.File;
import java.io.IOException;

/**
 * <b>Description : </b> 文件存在情况的业务结果对象
 * <p>
 * <b>created in </b> 2022/1/6
 * </p>
 * <p>
 * case1: 最开始有一个 FileExistCheck 类, 类里面有一个 getImgUrlCheck 方法, 还有个 FileExistCheckResult 类,
 * 使用 FileExistCheck.getImgUrlCheck(), 调用之后, 返回一个 FileExistCheckResult 结果,
 * case1-question: 这个比较大众的写法, 往外界暴漏两个类, 感觉有点冗余, 首先 FileExistCheckResult 结果, 没有什么可重用性,
 * FileExistCheck.getImgUrlCheck() 是一个功能, 但是一个功能暴漏两个类, 感觉有点冗余,
 * case1-缺点: 一个简单的功能往外面暴漏两个类, 不够简单, 维护时候比较乱.
 * case2: 在case1 的情况下, 将 FileExistCheckResult 变成一个内部类, 这样的话满足, 一个功能一个类的原则, 但是这样造成一个问题,
 * 但是其它类里面在引用 FileExistCheckResult 的时候, 会变成 FileExistCheck.FileExistCheckResult 的形式, 虽然结构行上, 使得代码方便维护.
 * 但是在使用的时候不够优雅.
 * case3: 将 FileExistCheckResult 变成外部类, 之后 getImgUrlCheck 变成内部类, 这样仅仅暴漏了一个类, 且在调用的时候比较方便.
 * case3缺点: 结构变了, 一个 pojo 里面加个业务方法, 感觉怪怪的, 调用者不熟悉的情况下, 根本是把逻辑结构性搞乱了.
 * case4: 在3的基础上, 将此种方式变成一个封装模式, 如这种方式叫做 BRO(business Resultant Object:业务结果对象), 它是一种 外层是一个结构, 其中静态方法里面有生成它的方法,
 * 在类名称上加以区分, 这样就可以比较好的避免上面的问题.
 * 适用:
 * 1. 一种方式往外面暴漏一种结果.
 * 2. 这种结果类没有什么重用性
 *
 * </p>
 *
 * @author CPF
 * @since 1.0
 **/
@Data
public class FileExistCheckBRO {
    /**
     * 路径类型
     */
    private PathUtils.PathType type;
    /**
     * 引用路径是否存在
     */
    private boolean exist;
    /**
     * 图片路径位置(markdown 文件路径字符串)
     */
    private String originalPath;
    /**
     * 图片路径位置(标准路径)
     */
    private String realImgPath;
    /**
     * 文件名称
     */
    private String imgFileName;

    private FileExistCheckBRO(PathUtils.PathType type, boolean exist, String realImgPath, String imgFileName) {
        this.type = type;
        this.exist = exist;
        this.realImgPath = realImgPath;
        this.imgFileName = imgFileName;
    }

    /**
     * 判断 file 是否是文件, 且是否存在, 并将结果封装为 ImgUrlCheck 对象
     */
    private static FileExistCheckBRO analyze(File file) {
        final boolean exist = file.exists() && file.isFile();
        String canonicalPath = "";
        try {
            canonicalPath = file.getCanonicalPath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new FileExistCheckBRO(PathUtils.PathType.ABSOLUTE_PATH, exist, canonicalPath, file.getName());
    }

    /**
     * 判断 URL 是否存在, 并将结果封装为 ImgUrlCheck 对象
     */
    public static FileExistCheckBRO analyze(String uriString, boolean checkExist) {
        final boolean exist = checkExist && HttpUtils.isUrlResExist(uriString);
        String fileName = BaseTool.findNameFromUrl(uriString);
        FileExistCheckBRO fileExistCheckBRO = new FileExistCheckBRO(PathUtils.PathType.WEB_URL, exist, uriString, fileName);
        fileExistCheckBRO.setOriginalPath(uriString);
        return fileExistCheckBRO;
    }

    /**
     * 分析路径, 并将结果封装为 ImgUrlCheck 对象
     */
    public static FileExistCheckBRO analyze(String path, CheckConfig config) {
        if (config.uriFilter != null && !config.uriFilter.test(path)) {
            return null;
        }
        final PathUtils.PathType pathType = PathUtils.getPathType(path);
        FileExistCheckBRO rst;
        switch (pathType) {
            case ROOT_PATH:
                if (!config.rootPathEnable) {
                    return null;
                }
                Validate.isTrue(StringUtils.isNotBlank(config.rootPath), "root 路径匹配启动时, rootPath 不能为空");
                rst = FileExistCheckBRO.analyze(new File(config.rootPath + path));
                break;
            case ABSOLUTE_PATH:
                if (!config.absolutePathEnable) {
                    return null;
                }
                rst = FileExistCheckBRO.analyze(new File(path));
                break;
            case RELATION_PATH:
                if (!config.relatePathEnable) {
                    return null;
                }
                Validate.isTrue(StringUtils.isNotBlank(config.parentPath), "相对路径匹配启动时, parentPath 不能为空");
                rst = FileExistCheckBRO.analyze(new File(config.parentPath + PathUtils.FILE_SPLIT_PATTERN + path));
                break;
            case WEB_URL:
                if (!config.webPathEnable) {
                    return null;
                }
                rst = FileExistCheckBRO.analyze(path, config.connectWeb);
                break;
            default:
                return null;
        }
        rst.setOriginalPath(path);
        return rst;
    }

}
